package net.xo68.destiny.core.json;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.List;
import java.util.Map;

/**
 *  json工具类
 * @author wuxie
 * @date 2018-7-13
 */
public class JsonMapper {

    private Logger logger=LoggerFactory.getLogger(JsonMapper.class);

    private static final TypeReference<?> MAP_TYPE = new MapTypeReference();
    private static final TypeReference<?> MAP_STRING_TYPE = new MapStringTypeReference();

    private static final TypeReference<?> LIST_TYPE = new ListTypeReference();

    private final ObjectMapper objectMapper;

    public JsonMapper(ObjectMapper objectMapper) {
        this.objectMapper = objectMapper;
    }

    public <T> String toString(T obj){
        return toString(obj,true);
    }

    public <T> String toString(T obj, boolean pretty){
        try {
            if(pretty){
                return objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(obj);
            }else {
                return objectMapper.writeValueAsString(obj);
            }

        } catch (JsonProcessingException e) {
            logger.error("序列化异常", e);
        }
        return null;
    }

    public <T> T parse(String jsonStr,Class<T> clazz){
        try {
            return objectMapper.readValue(jsonStr,clazz);
        } catch (IOException e) {
            logger.error("反序列化异常", e);
        }
        return null;
    }

    public <T> T parse(String jsonStr, JavaType javaType) {
        try {
            return (T) objectMapper.readValue(jsonStr, javaType);
        } catch (IOException e) {
            logger.error("parse json string error:" + jsonStr, e);
            return null;
        }
    }

    public <T> T parse(String jsonStr,TypeReference valueTypeRef){
        try {
            return (T) objectMapper.readValue(jsonStr,valueTypeRef);
        } catch (IOException e) {
            logger.error("反序列化异常", e);
        }
        return null;
    }
    public JavaType getJavaType(Type type){
        return objectMapper.getTypeFactory().constructType(type);
    }
    public JavaType getJavaType(TypeReference<?> typeRef){
        return objectMapper.getTypeFactory().constructType(typeRef);
    }
    public JavaType getCollectionJavaType(Class<? extends Collection> collectionClass,Class<?> elementClass){
        return objectMapper.getTypeFactory().constructCollectionType(collectionClass, elementClass);
    }
    public JavaType getMapJavaType(Class<? extends Map> mapClass,
                                    Class<?> keyClass, Class<?> valueClass){
        return objectMapper.getTypeFactory().constructMapType(mapClass,keyClass,valueClass);
    }
    public JavaType getParametricJavaType(Class<?> parametrized, Class<?>... parameterClasses){
        return objectMapper.getTypeFactory().constructParametricType(parametrized,parameterClasses);
    }
    public JavaType getParametricJavaType(Class<?> rawType, JavaType... parameterTypes){
        return objectMapper.getTypeFactory().constructParametricType(rawType,parameterTypes);
    }

    public Map<String, Object> parseMap(String json) {
        try {
            return (Map<String, Object>) objectMapper.readValue(json, MAP_TYPE);
        }
        catch (Exception ex) {
            logger.error("Cannot parse JSON", ex);
        }
        return null;
    }
    public Map<String, String> parseMapString(String json) {
        try {
            return (Map<String, String>) objectMapper.readValue(json, MAP_STRING_TYPE);
        }
        catch (Exception ex) {
            logger.error("Cannot parse JSON", ex);
        }
        return null;
    }

    public List<Object> parseList(String json) {
        try {
            return (List<Object>) objectMapper.readValue(json, LIST_TYPE);
        }
        catch (Exception ex) {
            logger.error("Cannot parse JSON", ex);
        }
        return null;
    }

    private static class MapTypeReference extends TypeReference<Map<String, Object>> {

    };
    private static class MapStringTypeReference extends TypeReference<Map<String, String>> {

    };

    private static class ListTypeReference extends TypeReference<List<Object>> {

    };
}
